﻿/*
Copyright (C) 2008 Google Inc.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

     http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

var g_gadget;

Gadget.MEDALS_REQUEST_INTERVAL_MS = 15 * 60 * 1000;
Gadget.MEDALS_URL = 'http://www.gmodules.com/ig/images/olympics/medals.js';
Gadget.MEDALS_BACKUP_URL = 'http://www.google.com/ig/olympics?type=medal';

Gadget.EVENTS_REQUEST_INTERVAL_MS = 15 * 60 * 1000;
Gadget.EVENTS_URL = 'http://www.gmodules.com/ig/images/olympics/events';
Gadget.EVENTS_BACKUP_URL = 'http://www.google.com/ig/olympics?type=events';

Gadget.NEWS_REQUEST_INTERVAL_MS = 30 * 60 * 1000;
Gadget.NEWS_URL = strings.NEWS_URL;
Gadget.MAX_NEWS_STORIES = 10;

Gadget.CHECK_DATE_INTERVAL_MS = 1 * 60 * 1000;

function Gadget() {
  this.isUserInteracting = false;

  this.newsDetails = null;
  this.eventDetails = null;

  this.settings = new Settings();
  this.dockedUi = new DockedUi(child(view, 'dockedContainer'));
  this.undockedUi = new UndockedUi(this, child(view, 'undockedContainer'));

  this.drawFlag();

  this.today = this.makeToday();
  this.eventDate = this.ensureValidDate(this.today);
  this.drawEventDate();

  this.checkDateTimer = view.setInterval(
      Utils.bind(this.checkDate, this), Gadget.CHECK_DATE_INTERVAL_MS);

  this.countries = null;
  this.events = null;
  this.stories = null;

  this.eventsBackupRequest = null;
  this.medalsBackupRequest = null;

  this.medalsDataSource = new DataSource(Gadget.MEDALS_URL,
      Gadget.MEDALS_REQUEST_INTERVAL_MS,
      Utils.bind(this.processMedalsData, this));
  this.eventsDataSource = new DataSource(this.makeEventsUrl(),
      Gadget.EVENTS_REQUEST_INTERVAL_MS,
      Utils.bind(this.processEventsData, this));
  this.newsDataSource = new DataSource(Gadget.NEWS_URL,
      Gadget.NEWS_REQUEST_INTERVAL_MS,
      Utils.bind(this.processNewsData, this));
}

Gadget.prototype.makeToday = function() {
  var today = new Date();

  if (this.getLanguageCode() != 'en') {
    return today;
  }

  var time = today.getTime();
  var utcTime = time + (today.getTimezoneOffset() * 60 * 1000);
  var beijingTime = utcTime + (8 * 60 * 60 * 1000);

  return new Date(beijingTime);
};

Gadget.prototype.getLanguageCode = function() {
  return framework.system.languageCode();
};

Gadget.prototype.makeEventsUrl = function() {
  var dateparam = this.eventDate.getDate();
  dateparam = dateparam < 10 ? '0' + dateparam : dateparam;

  var datePart = '-' + this.getLanguageCode().toLowerCase() + '-' +
      dateparam + '.js';

  return Gadget.EVENTS_URL + datePart;
};

Gadget.prototype.makeEventsBackupUrl = function() {
  var dateparam = this.eventDate.getDate();
  dateparam = dateparam < 10 ? '0' + dateparam : dateparam;

  var datePart = '&date=' + dateparam +
      '&hl=' + this.getLanguageCode() +
      '&oe=utf8';

  return Gadget.EVENTS_BACKUP_URL + datePart;
};

Gadget.prototype.makeMedalsUrl = function() {
  return Gadget.MEDALS_URL;
};

Gadget.prototype.makeMedalsBackupUrl = function() {
  var datePart = '&hl=' + this.getLanguageCode() +
      '&oe=utf8';

  return Gadget.MEDALS_BACKUP_URL + datePart;
};

Gadget.prototype.checkDate = function() {
  var today = this.makeToday();

  if (!Utils.isDateEqual(today, this.today)) {
    this.today = today;
    this.changeEventDate(this.today);
  }
};

Gadget.prototype.tryBackupMedalsData = function() {
  var url = this.makeMedalsBackupUrl();

  this.medalsBackupRequest = new XMLHttpRequest();
  var request = this.medalsBackupRequest;
  request.onreadystatechange = Utils.bind(this.handleBackupMedalsRequest, this);
  request.open('GET', url, true);
  request.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
  request.send();
};

Gadget.prototype.handleBackupMedalsRequest = function() {
  var request = this.medalsBackupRequest;

  if (request.readyState != 4) {
    return;
  }

  if (request.status == 200) {
    debug.trace('Retrieve succeeded for backup medals data.');
    this.processMedalsBackupData(request.responseText);
  } else {
    debug.error('Request error. Status: ' + request.status);
  }

  this.medalsBackupRequest = null;
};

Gadget.prototype.processMedalsData = function(data) {
  var countriesData;

  try {
    countriesData = eval('(' + data + ')').MedalCounts;
  } catch(e) {
    debug.error('Could not parse medals JSON.');
    this.tryBackupMedalsData();
    return;
  }

  this.parseMedalsData(countriesData);
  this.drawCountries();
};

Gadget.prototype.processMedalsBackupData = function(data) {
  var countriesData;

  try {
    countriesData = eval('(' + data + ')').MedalCounts;
  } catch(e) {
    debug.error('Could not parse medals backup JSON.');
    return;
  }

  this.parseMedalsData(countriesData);
  this.drawCountries();
};

Gadget.prototype.parseMedalsData = function(countriesData) {
  var countries = [];

  for (var i = 0; i < countriesData.length; ++i) {
    var countryData = countriesData[i];
    var country = new Country();
    country.shortName = countryData.ioc;
    country.goldCount = Number(countryData.gold);
    country.silverCount = Number(countryData.silver);
    country.bronzeCount = Number(countryData.bronze);
    countries.push(country);
  }

  this.countries = countries;
};

Gadget.prototype.makeCountriesSorter = function(property, isReverse) {
  if (!isReverse) {
    return function(a, b) {
      return a[property] - b[property];
    };
  } else {
    return function(a, b) {
      return b[property] - a[property];
    };
  }
};

Gadget.prototype.makeCountriesTotalSorter = function(isReverse) {
  if (!isReverse) {
    return function(a, b) {
      return a.getTotalCount() - b.getTotalCount();
    };
  } else {
    return function(a, b) {
      return b.getTotalCount() - a.getTotalCount();
    };
  }
};

Gadget.prototype.makeCountriesNameSorter = function(isReverse) {
  if (!isReverse) {
    return function(a, b) {
      x = a.shortName;
      y = b.shortName;

      return x < y ?
        -1 :
        x > y ? 1 : 0;
    };
  } else {
    return function(a, b) {
      x = a.shortName;
      y = b.shortName;

      return x < y ?
        1 :
        x > y ? -1 : 0;
    };
  }
};

Gadget.prototype.tryBackupEventsData = function() {
  var url = this.makeEventsBackupUrl();

  this.eventsBackupRequest = new XMLHttpRequest();
  var request = this.eventsBackupRequest;
  request.onreadystatechange = Utils.bind(this.handleBackupEventsRequest, this);
  request.open('GET', url, true);
  request.setRequestHeader('Content-Type', 'text/plain;charset=UTF-8');
  request.send();
};

Gadget.prototype.handleBackupEventsRequest = function() {
  var request = this.eventsBackupRequest;

  if (request.readyState != 4) {
    return;
  }

  if (request.status == 200) {
    debug.trace('Retrieve succeeded for backup events data.');
    this.processEventsBackupData(request.responseText);
  } else {
    debug.error('Request error. Status: ' + request.status);
  }

  this.eventsBackupRequest = null;
};

Gadget.prototype.processEventsData = function(data) {
  var eventsData;

  try {
    eventsData = eval('(' + data + ')').event_results;
  } catch(e) {
    debug.error('Could not parse events JSON.');
    debug.error(data);
    this.tryBackupEventsData();
    return;
  }

  this.parseEventsData(eventsData);
  this.drawEvents();
};

Gadget.prototype.processEventsBackupData = function(data) {
  var eventsData;

  try {
    eventsData = eval('(' + data + ');').event_results;
  } catch(e) {
    debug.error('Could not parse events backup JSON.');
    debug.error(data);
    this.events = [];
    this.drawEvents();

    return;
  }

  this.parseEventsData(eventsData);
  this.drawEvents();
};

Gadget.prototype.parseEventsData = function(eventsData) {
  var events = [];

  for (var i = 0; i < eventsData.length; ++i) {
    var eventData = eventsData[i];

    var ev = new Event();
    ev.id = eventData.id;
    ev.sportCode = ev.id.substr(0, 2);
    ev.gender = ev.id.substr(2, 1);
    ev.phase = eventData.phase;

    ev.eventDate = new Date(eventData.unix_time * 1000);
    ev.localStartTime = this.formatLocalStartTime(ev.eventDate);

    if (this.getLanguageCode() == 'en') {
      ev.localStartDatetime = 'Aug ' + ev.eventDate.getDate() + ' ' +
          ev.localStartTime;
    } else {
      ev.localStartDatetime = ev.localStartTime;
    }

    ev.time = eventData.time;
    ev.status = eventData.status;
    ev.description = eventData.sport ? eventData.sport :
        Sport.getSportName(ev.sportCode);

    var playersData = eventData.Players || [];

    for (var j = 0; j < playersData.length; ++j) {
      var playaData = playersData[j];

      var player = new Player();
      player.countryCode = playaData.ioc;

      if (playaData.athlete_en) {
        var tokens = playaData.athlete_en.split(',');
        if (tokens.length == 2) {
          player.name = tokens[1] + ' ' + tokens[0];
        } else {
          player.name = playaData.athlete_en;
        }
      } else {
        player.name = Country.buildName(player.countryCode);
      }
      player.score = playaData.score ? playaData.score : '';

      if (!player.score && playaData.win_indicator_en == 'winner') {
        player.score = strings.WINNER;
      }

      player.extra = playaData.medal_indicator;

      ev.players.push(player);
    }

    events.push(ev);
  }

  this.events = events;
};

Gadget.prototype.formatLocalStartTime = function(date) {
  var hours = date.getHours();
  var minutes = date.getMinutes();

  var amPm = strings.AM;

  if (hours >= 12) {
    hours -= 12;
    amPm = strings.PM;
  }

  if (hours === 0) {
    hours = 12;
  }

  minutes += '';
  if (minutes.length < 2) {
    minutes = '0' + minutes;
  }

  if (strings.AM == 'AM') {
    return hours + ':' + minutes + ' ' + amPm;
  } else {
    return amPm + hours + ':' + minutes;
  }
};

Gadget.prototype.processNewsData = function(data) {
  var doc = new DOMDocument();

  try {
    doc.resolveExternals = false;
    doc.validateOnParse = false;
    doc.setProperty('ProhibitDTD', false);
  } catch(e) {
    debug.error('Could not set MS specific properties.');
  }

  try {
    doc.loadXML(data);
  } catch(e) {
    debug.error('Could not load XML.');
    return;
  }

  var entries = parseRSS20(doc, Gadget.MAX_NEWS_STORIES);
  var stories = [];

  for (var i = 0; i < entries.length; ++i) {
    stories.push(new NewsItem(entries[i].content));
  }

  this.stories = stories;

  this.undockedUi.drawNews(this.stories);
};

Gadget.prototype.getEvents = function() {
  var sportCode = this.getSportFilter();
  var eventDate = this.eventDate;

  var events = [];

  if (!this.events) {
    return events;
  }

  for (var i = 0; i < this.events.length; ++i) {
    var ev = this.events[i];

    if (this.settings.isFilterEvents() &&
        !ev.isInvolvesCountry(this.settings.getCountry())) {
      continue;
    }
    if (!ev.sportCode) {
      continue;
    }
    if (sportCode && sportCode != ev.sportCode) {
      continue;
    }

    events.push(ev);
  }

  return events;
};

Gadget.prototype.getCountries = function() {
  var countries = [];

  if (!this.countries) {
    return countries;
  }

  var countryCode = this.settings.getCountry();

  var sortedCountries = this.countries.slice(0);
  var sortBy = this.settings.getSortBy();
  var isSortReverse = this.settings.isSortReverse();
  var sorter;

  if (sortBy == Settings.SORT_GOLD) {
    sorter = this.makeCountriesSorter('goldCount', isSortReverse);
  } else if (sortBy == Settings.SORT_SILVER) {
    sorter = this.makeCountriesSorter('silverCount', isSortReverse);
  } else if (sortBy == Settings.SORT_BRONZE) {
    sorter = this.makeCountriesSorter('bronzeCount', isSortReverse);
  } else if (sortBy == Settings.SORT_TOTAL) {
    sorter = this.makeCountriesTotalSorter(isSortReverse);
  } else if (sortBy == Settings.SORT_NAME) {
    sorter = this.makeCountriesNameSorter(isSortReverse);
  }

  sortedCountries.sort(sorter);

  for (var i = 0; i < sortedCountries.length; ++i) {
    var country = sortedCountries[i];

    if (this.settings.isMedalsFirst() &&
        country.shortName == countryCode) {
      countries.unshift(country);
    } else {
      countries.push(country);
    }
  }

  return countries;
};

Gadget.DOCKED_COUNTRIES_MAX = 4;

Gadget.prototype.getDockedCountries = function() {
  if (!this.countries) {
    return [];
  }

  var countries = this.countries.slice(0);
  countries.sort(this.makeCountriesSorter('goldCount', true));

  var dockedCountries = countries.slice(0, Gadget.DOCKED_COUNTRIES_MAX);
  // Check if favorite exists.
  var favorite = this.settings.getCountry();
  var isFound = false;

  for (var i = 0; i < dockedCountries.length; ++i) {
    if (dockedCountries[i].shortName == favorite) {
      isFound = true;

      if (this.settings.isMedalsFirst() && i !== 0) {
        var temp = dockedCountries[i];
        dockedCountries[i] = dockedCountries[0];
        dockedCountries[0] = temp;
      }
      break;
    }
  }

  // Ensure favorite is among the list.
  if (!isFound) {
    for (i = 0; i < countries.length; ++i) {
      if (countries[i].shortName == favorite) {
        dockedCountries.pop();
        if (this.settings.isMedalsFirst()) {
          dockedCountries.unshift(countries[i]);
        } else {
          dockedCountries.push(countries[i]);
        }
        break;
      }
    }
  }

  return dockedCountries;
};

Gadget.prototype.drawEvents = function() {
  this.drawEventDate();
  this.undockedUi.drawEvents(this.getEvents(), this.settings);
};

Gadget.prototype.drawCountries = function() {
  this.undockedUi.drawCountries(this.getCountries());
  this.undockedUi.drawSortOrder(this.settings.getSortBy(),
      this.settings.isSortReverse());
  this.dockedUi.draw(this.getDockedCountries());
};

Gadget.prototype.drawEventDate = function() {
  this.undockedUi.drawEventDate(this.eventDate);
};

Gadget.prototype.drawFlag = function() {
  this.undockedUi.drawFlag(Country.buildFlagPath(this.settings.getCountry()));
};

Gadget.prototype.onDock = function() {
  view.width = this.dockedUi.getWidth();
  view.height = this.dockedUi.getHeight();
  this.dockedUi.show();
  this.undockedUi.hide();
};

Gadget.prototype.onUndock = function() {
  view.width = this.undockedUi.getWidth();
  view.height = this.undockedUi.getHeight();
  this.dockedUi.hide();
  this.undockedUi.show();
};

Gadget.prototype.onPopOut = function() {
  this.dockedUi.hide();
  this.undockedUi.show();
};

Gadget.prototype.onPopIn = function() {
  this.dockedUi.show();
  this.undockedUi.hide();
};

Gadget.prototype.onOptionChanged = function() {
  if (event.propertyName == Settings.COUNTRY_KEY) {
    this.drawFlag();
    this.drawEvents();
    this.drawCountries();
  } else if (event.propertyName == Settings.IS_FILTER_EVENTS_KEY) {
    this.drawEvents();
  } else if (event.propertyName == Settings.IS_MEDALS_FIRST_KEY) {
    this.drawCountries();
  }
};

Gadget.prototype.showNewsDetails = function(item) {
  if (item == this.newsDetails) {
    plugin.CloseDetailsView();
    return;
  }

  var html = item.description;

  var detailsView = new DetailsView();
  detailsView.html_content = true;
  detailsView.SetContent('', undefined, html, false, 0);
  plugin.ShowDetailsView(detailsView, item.title, gddDetailsViewFlagToolbarOpen,
      Utils.bind(this.handleNewsDetailsFeedback, this));

  this.newsDetails = item;
};

Gadget.prototype.openNewsInBrowser = function(item) {
  framework.openUrl(item.link);
};

Gadget.prototype.handleNewsDetailsFeedback = function(flags) {
  if (flags == gddDetailsViewFlagToolbarOpen && this.newsDetails) {
    framework.openUrl(this.newsDetails.link);
  }

  this.newsDetails = null;
};

Gadget.prototype.showEventDetails = function(ev) {
  if (ev == this.eventDetails) {
    plugin.CloseDetailsView();
    return;
  }

  var detailsView = new DetailsView();
  detailsView.SetContent('', undefined, 'event_details.xml', false, 0);
  detailsView.detailsViewData.putValue('event', ev);
  plugin.ShowDetailsView(detailsView, ev.description, gddDetailsViewFlagNone,
      Utils.bind(this.clearEventDetails, this));

  this.eventDetails = ev;
};

Gadget.prototype.clearEventDetails = function() {
  this.eventDetails = null;
};

Gadget.prototype.setSportFilter = function(sportCode) {
  this.settings.setSport(sportCode);
  this.drawEvents();
};

Gadget.prototype.clearSportFilter = function() {
  this.settings.setSport('');
  this.undockedUi.eventsPanel.clearFilter();
  this.drawEvents();
};

Gadget.prototype.getSportFilter = function() {
  return this.settings.getSport();
};


Gadget.MIN_DATE = new Date(2008, 7, 6);
Gadget.MAX_DATE = new Date(2008, 7, 24);

Gadget.prototype.changeEventDate = function(newDate) {
  if (this.eventsBackupRequest) {
    debug.warning('Cancelling backup events data request.');
    this.eventsBackupRequest.abort();
  }
  this.undockedUi.eventsPanel.drawLoading();
  this.eventDate = this.ensureValidDate(newDate);
  this.drawEventDate();
  this.eventsDataSource.url = this.makeEventsUrl();
  this.eventsDataSource.send();
};

Gadget.prototype.ensureValidDate = function(date) {
  if (date.getTime() > Gadget.MAX_DATE.getTime()) {
    return new Date(Gadget.MAX_DATE);
  }
  if (date.getTime() < Gadget.MIN_DATE.getTime()) {
    return new Date(Gadget.MIN_DATE);
  }

  return date;
};

Gadget.prototype.increaseEventDate = function() {
  var newDate = new Date(this.eventDate.getFullYear(),
      this.eventDate.getMonth(),
      this.eventDate.getDate() + 1);

  this.changeEventDate(newDate);
};

Gadget.prototype.decreaseEventDate = function() {
  var newDate = new Date(this.eventDate.getFullYear(),
      this.eventDate.getMonth(),
      this.eventDate.getDate() - 1);

  this.changeEventDate(newDate);
};

Gadget.prototype.adjustEventsFilterBorder = function() {
  this.undockedUi.adjustEventsFilterBorder();
};

Gadget.prototype.hideEventsFilterBorder = function() {
  this.undockedUi.hideEventsFilterBorder();
};

Gadget.prototype.setSortOrReverse = function(sortBy) {
  if (sortBy == this.settings.getSortBy()) {
    this.settings.setSortReverse(!this.settings.isSortReverse());
  } else {
    this.settings.setSortBy(sortBy);
    this.settings.setSortReverse(true);
  }

  this.drawCountries();
};

Gadget.prototype.showAllEvents = function() {
  this.settings.setFilterEvents(false);
  this.clearSportFilter();
};

function _onOpen() {
  g_gadget = new Gadget();
  // Assume it's docked.
  g_gadget.onDock();
}

function _onDock() {
  g_gadget.onDock();
}

function _onUndock() {
  g_gadget.onUndock();
}

function _onEventDateLeft() {
  g_gadget.decreaseEventDate();
}

function _onEventDateRight() {
  g_gadget.increaseEventDate();
}

function _onOptionChanged() {
  g_gadget.onOptionChanged();
}

function _onClick() {
  g_gadget.hideEventsFilterBorder();
}

function _onFilterClick() {
  if (g_gadget) {
    g_gadget.adjustEventsFilterBorder();
  }
}

function _onGoldClick() {
  g_gadget.setSortOrReverse(Settings.SORT_GOLD);
}

function _onSilverClick() {
  g_gadget.setSortOrReverse(Settings.SORT_SILVER);
}

function _onBronzeClick() {
  g_gadget.setSortOrReverse(Settings.SORT_BRONZE);
}

function _onTotalClick() {
  g_gadget.setSortOrReverse(Settings.SORT_TOTAL);
}

function _onNameClick() {
  g_gadget.setSortOrReverse(Settings.SORT_NAME);
}

function _onShowAllEventsClick() {
  g_gadget.showAllEvents();
}

function _onMouseOver() {
  g_gadget.isUserInteracting = true;
}

function _onMouseOut() {
  g_gadget.isUserInteracting = false;
}

function isLinux() {
  return framework.runtime.osName == 'Linux';
}

function _onPopOut() {
  if (isLinux()) {
    g_gadget.onUndock();
  }
}

function _onPopIn() {
  if (isLinux()) {
    g_gadget.onDock();
  }
}
